/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MyThread;

import MyLib.Comvar;
import MyLib.MyPacket;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketTimeoutException;

/**
 *
 * @author QuangHau
 */
public class UploadChunk extends Thread {

    private DatagramPacket packet;

    public UploadChunk(DatagramPacket rcvpkt) {
        packet = rcvpkt;

    }

    public void run() {
        Comvar.writeLog(1, UploadChunk.class.getName(), "BEGIN UPLOAD CHUNK THREAD " + Long.toString(this.getId()));
        //Phân tích gói tin yêu cầu xin download chunk
        MyPacket packetRecv = new MyPacket(packet);
        String stRcv = new String(packetRecv.getData(), 0, packetRecv.getData().length);
        Comvar.writeLog(3, DownloadChunk.class.getName(), "RECEIVE " + packet.getAddress().getHostAddress() + 
                        ":" + packet.getPort() +  " [Request download chunk " + stRcv + "]");
        System.out.println("Nhan yeu cau download  chunk " + stRcv + " tu port" + packet.getPort());

        //Tìm Chunk
        String[] arrStr = stRcv.split(";");
        String path = "Data\\" + arrStr[0] + "\\" + arrStr[1] + ".chunk";
        File file = new File(path);

        if (file.exists()) {
            //Gửi lại gói tin đồng ý cho down load - chờ xác nhận
            String stSend = stRcv;
            try {
                DatagramSocket socket = new DatagramSocket();
                byte option = 0;
                byte type = 100;
                DatagramPacket sendPacket = MyPacket.createPacket(stSend.getBytes(), packet.getAddress(), packet.getPort(), type, option, 0, 0);
                socket.send(sendPacket);
                Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + sendPacket.getAddress().getHostAddress() + 
                        ":" + sendPacket.getPort() +  " [Accept download chunk " + stSend + "]");
                System.out.println("Đong y download chunk  " + stSend);

                //Nhan goi tin xac nhan
                socket.setSoTimeout(3000);
                boolean flag = false;
                try {
                    byte[] buf = new byte[1024];
                    DatagramPacket rcv_packet = new DatagramPacket(buf, buf.length);
                    socket.receive(rcv_packet);
                    flag = true;
                } catch (SocketTimeoutException e) {
                    //Hết thời gian, hủy tiến trình
                    flag = false;
                }

                //gui nhan data-------------------------------------------------
                if (flag) {
                    //doc file
                    InputStream inStream = new BufferedInputStream(new FileInputStream(file));
                    int FILE_SIZE = (int) file.length();
                    int SIZE = 1000;
                    byte[] temporary = new byte[FILE_SIZE];
                    inStream.read(temporary, 0, FILE_SIZE);
                    int seq = 0;
                    int ack = 0;
                    while (seq < FILE_SIZE) {
                        int bytesRemaining = FILE_SIZE - seq;
                        if (bytesRemaining < SIZE) // Remaining Data Part is Smaller Than CHUNK_SIZE
                        // CHUNK_SIZE is assigned to remain volume
                        {
                            SIZE = bytesRemaining;
                        }

                        //Gio tin gui
                        option = 1;//seq
                        type = 100;
                        byte[] data = new byte[SIZE];
                        System.arraycopy(temporary, seq, data, 0, SIZE);
                        ack = seq + SIZE;
                        DatagramPacket sendPacketData = MyPacket.createPacket(data, packet.getAddress(), packet.getPort(), type, option, seq, ack);

                        //Goi tin nhan
                        byte[] rcvbuf = new byte[1024];
                        DatagramPacket rcv_packet = new DatagramPacket(rcvbuf, rcvbuf.length);

                        //Send DatagramPacket - bat dong ho
                        socket.send(sendPacketData);
                        Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + sendPacketData.getAddress().getHostAddress() + 
                        ":" + sendPacketData.getPort() +  " [DATA SEQ: " +  seq + " OF CHUNK "+ stSend +"]");
                        System.out.println("gui data cho client" + packet.getAddress() + " seq " + seq);
                        socket.setSoTimeout(3000);
                        int cout = 0;
                        while (true) {
                            try {
                                //Nhan ACK
                                socket.receive(rcv_packet);
                                MyPacket packetDataRecv = new MyPacket(rcv_packet);
                                Comvar.writeLog(3, DownloadChunk.class.getName(), "RECEIVE " + rcv_packet.getAddress().getHostAddress() + 
                                ":" + rcv_packet.getPort() +  " [ACK: " + packetDataRecv.getAck() + " OF CHUNK " + stSend +"]");
                                System.out.println("Nhan ACK: " + packetDataRecv.getAck());
                                if (packetDataRecv.getAck() == ack) {
                                    seq = ack;
                                } else {
                                    seq = packetDataRecv.getAck();
                                }
                                ack += SIZE;
                                cout = 0;
                                break;
                            } catch (SocketTimeoutException e) {
                                //Hết  time out - gửi lại
                                System.out.println("Hết time out -- gửi lại");
                                socket.send(sendPacketData);
                                Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + sendPacketData.getAddress().getHostAddress() + 
                        ":" + sendPacketData.getPort() +  " [DATA SEQ: " +  seq + " OF CHUNK "+ stSend +"]");
                                System.out.println("gui data cho client" + packet.getAddress() + " seq " + seq);

                                if (cout == 5) {
                                    break;
                                }
                                cout++;
                                socket.setSoTimeout(3000);
                            }
                        }

                        if (cout == 5) {
                            break;
                        }
                    }

                    type = 100;
                    option = 4;
                    byte[] dataNull = new byte[1];
                    DatagramPacket sendPacketExit = MyPacket.createPacket(dataNull, packet.getAddress(), packet.getPort(), type, option, 0, 0);
                    socket.send(sendPacketExit);
                    Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + sendPacketExit.getAddress().getHostAddress() + 
                        ":" + sendPacketExit.getPort() +  " [EXIT]");
                    System.out.println("--------------------------------Upload Xong" + sendPacket.getPort());

                }
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        Comvar.writeLog(1, UploadChunk.class.getName(), "END UPLOAD CHUNK THREAD " + Long.toString(this.getId()));
    }
}
